package excel

import (
	"encoding/csv"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sort"
	"sync"

	"github.com/xuri/excelize/v2"
)

// csvToExcel 将CSV文件转换为Excel文件
// csvPath: 输入的CSV文件路径
// excelPath: 输出的Excel文件路径
func CsvToExcel(csvPath, excelPath string) error {
	// 打开CSV文件
	csvFile, err := os.Open(csvPath)
	if err != nil {
		return fmt.Errorf("无法打开CSV文件: %v", err)
	}
	defer csvFile.Close()

	// 读取CSV内容
	csvReader := csv.NewReader(csvFile)
	csvRecords, err := csvReader.ReadAll()
	if err != nil {
		return fmt.Errorf("读取CSV文件失败: %v", err)
	}

	// 创建Excel文件
	excelFile := excelize.NewFile()
	defer func() {
		// 关闭Excel文件
		if err := excelFile.Close(); err != nil {
			fmt.Printf("关闭Excel文件失败: %v\n", err)
		}
	}()

	// 获取默认工作表
	sheetName := "Sheet1"
	index, err := excelFile.NewSheet(sheetName)
	if err != nil {
		return fmt.Errorf("创建工作表失败: %v", err)
	}

	// 将CSV数据写入Excel
	for rowIdx, row := range csvRecords {
		for colIdx, value := range row {
			// 转换行列索引为Excel单元格坐标（如A1, B2等）
			cell, err := excelize.CoordinatesToCellName(colIdx+1, rowIdx+1)
			if err != nil {
				return fmt.Errorf("转换单元格坐标失败: %v", err)
			}
			// 设置单元格值
			if err := excelFile.SetCellValue(sheetName, cell, value); err != nil {
				return fmt.Errorf("设置单元格值失败: %v", err)
			}
		}
	}

	// 设置默认工作表
	excelFile.SetActiveSheet(index)
	log.Println("自动调整列宽")
	AutoAdjustAllColumnWidth(excelFile, sheetName)
	// 创建输出目录（如果不存在）
	if err := os.MkdirAll(filepath.Dir(excelPath), 0755); err != nil {
		return fmt.Errorf("创建输出目录失败: %v", err)
	}

	log.Println("保存Excel文件")
	if err := excelFile.SaveAs(excelPath); err != nil {
		return fmt.Errorf("保存Excel文件失败: %v", err)
	}

	return nil
}
func AutoAdjustAllColumnWidth(excelFIle *excelize.File, sheet string) {
	columns, _ := GetDataColumns(excelFIle, sheet)
	log.Printf("表格列数：%d\n", len(columns))

	keys := SortKeys(columns)

	var wg sync.WaitGroup
	for _, excelColIdx := range keys {
		wg.Add(1)
		go AutoAdjustColumnWidthSync(excelFIle, sheet, excelColIdx, &wg)
	}
	wg.Wait()
}

func SortKeys(columns map[int]bool) []int {
	// 创建一个切片来保存所有的键
	keys := make([]int, 0, len(columns))
	// 遍历 map，把所有键存到切片中
	for k := range columns {
		keys = append(keys, k)
	}
	// 对切片中的键进行升序排序
	sort.Ints(keys)
	return keys
}

func AutoAdjustColumnWidthSync(excelFIle *excelize.File, sheet string, excelColIdx int, wg *sync.WaitGroup) {
	defer wg.Done()
	err := AutoAdjustColumnWidth(excelFIle, sheet, excelColIdx)
	if err != nil {
		log.Printf("第[%d]列宽度调整出错, %v\n", excelColIdx, err)
	} else {
		log.Printf("第[%d]列宽度调整完成\n", excelColIdx)
	}
}
func AutoAdjustColumnWidth(excelFIle *excelize.File, sheet string, excelColIdx int) error {
	allCols, err := excelFIle.GetCols(sheet)
	if err != nil {
		return err
	}

	width := GetColWith(allCols[excelColIdx-1])
	log.Printf("第[%d]列宽[%f]\n", excelColIdx, width)

	colName, err := excelize.ColumnNumberToName(excelColIdx)
	if err != nil {
		fmt.Printf("列索引 %d 转换为列名失败：%v\n", excelColIdx, err)
	}
	return excelFIle.SetColWidth(sheet, colName, colName, width)
}

func GetColWith(targetCol []string) float64 {
	allWith := 0
	for _, cell := range targetCol {
		allWith = allWith + len(cell)
	}

	width := float64(allWith)/float64(len(targetCol))*1.0 + 4 // 调整比例因子
	return width
}

func GetDataColumns(excelFIle *excelize.File, sheet string) (map[int]bool, error) {
	// 3. 收集所有有数据的列索引（去重）
	dataColumns := make(map[int]bool) // key:列索引（从 1 开始），value:是否存在

	rows, err := excelFIle.GetRows(sheet)
	if err != nil {
		return nil, err
	}

	// 遍历每一行，收集有数据的列
	for _, row := range rows {
		// row 是当前行的单元格数据切片（索引从 0 开始，对应列 A、B、C...）
		// 注意：excelize 的 GetRows 返回的 row 切片长度 = 该行最后一个非空单元格的列索引（0 开始）+1
		// 例如：行数据为 ["A1", "", "C1"]，row 长度为 3（索引 0:A，1:B，2:C），但 B 列是空值，需过滤
		for colIdx, cellValue := range row {
			// 只收集非空单元格对应的列（colIdx 是 0 开始，需转换为 Excel 列索引 1 开始）
			if cellValue != "" {
				excelColIdx := colIdx + 1 // Excel 列索引从 1 开始（A=1，B=2...）
				dataColumns[excelColIdx] = true
			}
		}
	}
	return dataColumns, nil
}
